//
// Created by liugang on 9/17/25.
//
#include <iostream>

#include "nodes.h"
#include "vars.h"

namespace test3 {

struct Model {
};

struct Instance {
    Model* model;

    // 模型参数
    real r{1};
    real mm{2};
    real isconst{0};

    // 模型中间变量
    real Ir{0};
    real i{0};
    real conductance{0};

    auto show_all() -> void {
        fprintf(stdout, "\n");
        fprintf(stdout, "%p inst->r = %lf\n", &r, r);
        fprintf(stdout, "%p inst->mm = %lf\n", &mm, mm);
        fprintf(stdout, "%p inst->isconst = %lf\n", &isconst, isconst);
        fprintf(stdout, "%p inst->Ir = %lf\n", &Ir, Ir);
        fprintf(stdout, "%p inst->i = %lf\n", &i, i);
        fprintf(stdout, "%p inst->conductance = %lf\n", &conductance, conductance);
    }
};

enum LOC_ID : int32_t {
    LOCID_P,
    LOCID_N,

    LOCID_COUNT,
};

/**
 * 简化处理，避免demo搞得过于复杂
 */
struct Context {
    Instance* inst;
    real sol[LOCID_COUNT]{0, 0};

    auto var(Var var) -> real& {
        return sol[var.loc_id];
    }
};


/**
 * 简化处理，避免demo搞得过于复杂
 */
auto AccessV(void* c, int32_t loc_id) -> real {
    Context* ctx = static_cast<Context*>(c);
    return ctx->sol[loc_id];
}

auto AccessI(void* c, int32_t loc_id) -> real {
    Context* ctx = static_cast<Context*>(c);
    return ctx->sol[loc_id];
}

auto test() -> void {
    Model vModel;
    Instance vInstance;

    Model* model = &vModel;
    Instance* inst = &vInstance;

    FLOW flow;

    // 流程编排阶段，inst 和 model 就已经创建好了
    flow.bind_target(inst, model);

    // 注册本 flow 的 access 函数
    auto V = flow.access("V", AccessV);
    auto I = flow.access("I", AccessI);

    // 定义求变量
    auto Vp = flow.var("V(p)", V(LOCID_P));
    auto Vn = flow.var("V(n)", V(LOCID_N));

    real Ipn = 0;

    // 简单公式：
    // I(p,n) = sin(V(p));

    // 定义计算流程
    // clang-format off
    flow //
    //.EXPR(ref(Ipn) = sin(Vp- Vn))
    .EXPR(ref(Ipn) =(Vp- Vn)* 3.0)
    .COMMIT()
    ;
    // clang-format on

    // 将语法树打印出来看下效果
    print_node(flow.root(), 0, PF_PRINTCHILDREN, stdout);

    // 执行时：
    Context context{inst}; // NOTICE：Context 在执行时才是有效的
    flow.bind_context(&context);

    // 给求解变量赋予初始值
    context.var(Vp) = 1;
    context.var(Vn) = 0;

    fprintf(stdout, "------------\n");
    // 先做计算
    eval_stmt(&flow, flow.root());

    fprintf(stdout, "------------\n");
    inst->show_all();
    fprintf(stdout, "I(p,n) = %lf\n", Ipn);

    fprintf(stdout, "------------\n");

    // 再做求导
    deriv_stmt(&flow, flow.root(), 1.0);
    fprintf(stdout, "\nResult:\n");
    fprintf(stdout, "dFdV(p)=%lf\n", flow.var_value(Vp));
    fprintf(stdout, "dFdV(n)=%lf\n", flow.var_value(Vn));
}

}